// Copyright (C) 2005 Greg Lavender <lavender@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// 	$Id: Synchronized.hh 60 2005-07-25 18:40:11Z richetl $	
//

/* Synch.h - a C++ class that provides a mutex and condition variable using
 * POSIX threads on Unix/Linux. The nested Scope class is used to provide
 * a scope based lock/unlock abstraction. Assuming some class X inherits
 * from the Synchronized class, a method of X would do the following to
 * acquire the lock on entry to the scope of the method and have it 
 * automatically released on exit from the scope of the method:
 *
 * #include "Sync.h"
 * ...
 * class X : public Synchronized {
 * public:
 *   ...
 *   some_method() { Synchronized::Scope mutex(this); ...; }
 *   ...
 * }; 
 */

#ifndef SYNCH_H
#define SYNCH_H

#include <pthread.h>
#include <assert.h>

namespace lee {
class Synchronized 
{

    pthread_mutex_t m;  // mutex variable
    pthread_cond_t  c;  // condition variable

protected:

    /* use this class to associate the mutex lock/unlock with the scope
     * of a procedure
     */
    class Scope {
        Synchronized* obj;
    public:
        Scope(Synchronized* s) : obj(s)  { pthread_mutex_lock(&obj->m); }
        ~Scope() { 
	  assert(obj != NULL);
	  pthread_mutex_unlock(&obj->m); 
	}
    };

public:
		
    Synchronized() { 
       // initialize the mutex and condvar on construction
       pthread_mutex_init(&m, 0);
       pthread_cond_init(&c, 0);
    }

    ~Synchronized() {
	// destroy the mutex and condvar on destruction
        pthread_mutex_destroy(&m);
        pthread_cond_destroy(&c);
    }

    // map Java-like wait, notify and notifyAll onto pthread equivalents

    void wait() { pthread_cond_wait(&c, &m); }
    void notify() { pthread_cond_signal(&c); }
    void notifyAll() { pthread_cond_broadcast(&c); }
};
}
#endif // SYNCH_H
